# -*- encoding: utf-8 -*-
"""Tools to manage the internal representation of the code


.. moduleauthor:: Ruyman Reyes Castro <rreyes@ull.es>

"""

#from C import  c_ast
#from C99 import  c_ast

import cStringIO

import copy as Copy

from yacf.Frontend.Common.IRNode import IRNodeVisitor, IRNode

from yacf.Frontend.SymbolTable import SymbolTable, SymbolTableBuilder

from yacf.Frontend.Shortcuts import getCurrentLanguageAst
from yacf.Tools.Tree import getFileNode
c_ast = getCurrentLanguageAst()

class CompoundAnnotation(IRNodeVisitor):
    """
        
    """
    def __init__(self,*args, **kwargs):
        print "*** DEPRECATION WARNING: CompoundAnnotation class is here only for backwards compatibility."
        print "*** It might produce collateral damage"
        super(CompoundAnnotation, self).__init__(*args, **kwargs)
        
        
    def visit_Compound(self, node):
        setattr(node, 'stmts', [])
        setattr(node, 'decls', [])
        for elem in node.block_items:
            if isinstance(elem, c_ast.Decl):
                node.decls.append(elem)
            else:
                node.stmts.append(elem)       
 

class AstToIR(object):
    """ Transform a C ast to the internal representation (Flyweight pattern)

    """

    _instanceCache = {}


    def __init__(self, Writer, ast):
        def fast_write(node):
            """Write the internal representation with the given Writer
                :param node: Node to write
            """
            writeIO = cStringIO.StringIO()
            cw = Writer(stream = writeIO)
            cw.visit(node)
            return writeIO.getvalue()

        # This need to be done at this point to use Writer inside a closure
        # so the __str__ uses a predefined writer
        # Overload __str__ method on Node class
        # Will apply to all instances !!
        IRNode.__str__ = fast_write
        self._symbolTable = None
        self._ast = ast
        # self._ast = getFileNode(ast)

    @staticmethod
    def deep_first_search(root, visited = None, preorder_process  = lambda x: None):
        """Given a starting vertex, root, do a depth-first search.

            :param root: Root to start search
            :param visited: List of already visited nodes
            :param preorder_process: Function to apply in all nodes
            
        """
        to_visit = [] 
        if visited is None: visited = set()
    
        to_visit.append(root) # Start with root
        while len(to_visit) != 0:
                  v = to_visit.pop()
                  if v not in visited and v:
                             visited.add(v)
                             preorder_process(v)
                             to_visit.extend(v.children())

    def link_all_parents(self, ast):
          """ Function to link the nodes of the AST in reverse order, using a parent attribute in each node 

                :param ast: Ast to relink
          """
          def link_parent(node):
                  for child in node.children():
			if child:
                             child.parent = node

          AstToIR.deep_first_search(root = ast, visited = None, preorder_process = link_parent)


    @staticmethod
    def link_subtree_parents(ast):
          """ Function to link the nodes of the AST in reverse order, using a parent attribute in each node 

                :param ast: Ast to relink
          """
          def link_parent(node):
                  for child in node.children():
			if child:
                             child.parent = node

          AstToIR.deep_first_search(root = ast, visited = None, preorder_process = link_parent)

    def annotate(self):
        """ Apply transformations needed to migrate from a c_ast to a InternalRepresentation.
             
                - Link all parents
                - Update symbol table
            
        """
        self.link_all_parents(self._ast)  
        self._symbolTable = SymbolTable()
        tsv = SymbolTableBuilder(symbol_table = self._symbolTable)
        tsv.visit(self._ast)
        # CompoundAnnotation().visit(self._ast)

    def update(self, node):
        """ Update parent links
            
            :param node: FileAST node to start conversion
        """
        self.annotate(node)  
        return node


    @property
    def symbolTable(self):
        """ Returns the symbol table for the current ast
            
            :param node: FileAST node to start conversion
        """
        if not self._symbolTable:
                self.annotate()
        return self._symbolTable

    @property
    def ast(self):
        """ Return the ast attached to this IR """
        return self._ast

    @staticmethod 
    def deepcopySubtree(subtree):
        new_var = subtree.__deepcopy__();
        AstToIR.link_subtree_parents(new_var)
        setattr(new_var, 'parent', subtree.parent)
        return new_var
    
